package com.alex.webnote.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Repository;

import com.alex.common.persistent.BaseDao;
import com.alex.webnote.domain.WebNotePO;
import com.alex.webnote.domain.WebNoteState;

@Repository
public class WebNoteDao extends BaseDao {

	public void save(final WebNotePO po, final String author_,
			final boolean isInsert) {
		dao(new Run<Boolean>() {
			protected Boolean run(EntityManager em) {
				po.setUpdateTime(new Date());
				if (!isInsert) {
					// TODO　check user could update
					if (author_ != null && author_.equals(po.getAuthor_())) {
						em.merge(po);
						return true;
					} else {
						return false;
					}
				} else {
					po.setId(null);
					em.persist(po);
					return true;
				}
			}
		}, false);
	}

	private static final String LIST4LIST = "select id, name, alias from "
			+ WebNotePO.class.getName()
			+ " tb where tb.username = ? order by updateTime desc";

	@SuppressWarnings("unchecked")
	public List<WebNotePO> query4List(final int first, final int max,
			final String username) {
		return (List<WebNotePO>) dao(new Run<List<WebNotePO>>() {

			protected List<WebNotePO> run(EntityManager em) {
				Query query = em.createQuery(LIST4LIST);
				query.setParameter(1, username);
				query.setFirstResult(first);
				query.setMaxResults(max);
				List<Object[]> list = query.getResultList();

				List<WebNotePO> rt = new ArrayList<WebNotePO>(list.size());
				if (list != null) {
					for (Object[] objects : list) {
						BeanWrapper bw = new BeanWrapperImpl(WebNotePO.class);
						bw.setPropertyValue("id", objects[0]);
						bw.setPropertyValue("name", objects[1]);
						bw.setPropertyValue("alias", objects[2]);
						rt.add((WebNotePO) bw.getWrappedInstance());
					}
				}

				return rt;
			}
		}, true);
	}

	private static final String LIST4SUMMARYBYUPDATETIME = "from "
			+ WebNotePO.class.getName()
			+ " tb where tb.state>=? order by tb.updateTime desc";

	private static final String LIST4SUMMARYBYHOTS = "from "
			+ WebNotePO.class.getName()
			+ " tb where tb.state>=? order by tb.hots desc";

	public List<WebNotePO> querySummaryByUpdatetime(int size) {
		return querySummary(0, size, LIST4SUMMARYBYUPDATETIME,
				WebNoteState.PUBLISHED.ordinal());
	}

	private static final String QUERY_ALL_BY_CREATETIME = "select id,name,alias,createTime,updateTime,hots from "
			+ WebNotePO.class.getName() + " tb order by createTime desc";

	/**
	 * Object is "id,name,alias,createTime,updateTime,hots"
	 * 
	 * @param pagenum
	 * @param pagesize
	 * @return
	 */
	public List<Object[]> queryAllByCreateTimePage(final int pagenum,
			final int pagesize) {
		return (List<Object[]>) dao(new Run<List<Object[]>>() {
			protected List<Object[]> run(EntityManager em) {
				Query query = em.createQuery(QUERY_ALL_BY_CREATETIME);
				query.setFirstResult((pagenum - 1) * pagesize);
				query.setMaxResults(pagesize);
				@SuppressWarnings("unchecked")
				List<Object[]> list = query.getResultList();
				return list;
			}
		}, true);
	}

	public List<WebNotePO> querySummaryByHots(int size) {
		return querySummary(0, size, LIST4SUMMARYBYHOTS,
				WebNoteState.PUBLISHED.ordinal());
	}

	private List<WebNotePO> querySummary(final int first, final int max,
			final String sqlByWhat, final int state) {
		return (List<WebNotePO>) dao(new Run<List<WebNotePO>>() {
			protected List<WebNotePO> run(EntityManager em) {
				Query query = em.createQuery(sqlByWhat);
				query.setParameter(1, state);
				query.setFirstResult(first);
				query.setMaxResults(max);
				@SuppressWarnings("unchecked")
				List<WebNotePO> rlist = (List<WebNotePO>) query.getResultList();
				return rlist;
			}
		}, true);
	}

	private static final String LIST_4_EXPORT = "select name,tags,noteContent from "
			+ WebNotePO.class.getName()
			+ " tb where tb.username = ? order by updateTime desc";

	public List<WebNotePO> list4Export(final int first, final int max,
			final String username) {
		return (List<WebNotePO>) dao(new Run<List<WebNotePO>>() {

			protected List<WebNotePO> run(EntityManager em) {
				Query query = em.createQuery(LIST_4_EXPORT);
				query.setParameter(1, username);
				query.setFirstResult(first);
				query.setMaxResults(max);
				@SuppressWarnings("unchecked")
				List<Object[]> list = query.getResultList();

				if (list != null) {
					List<WebNotePO> rt = new ArrayList<WebNotePO>(list.size());
					for (Object[] objects : list) {
						BeanWrapper bw = new BeanWrapperImpl(WebNotePO.class);
						bw.setPropertyValue("name", objects[0]);
						bw.setPropertyValue("tags", objects[1]);
						bw.setPropertyValue("noteContent", objects[2]);
						rt.add((WebNotePO) bw.getWrappedInstance());
					}
					return rt;
				} else {
					return new ArrayList<WebNotePO>(0);
				}

			}
		}, true);
	}

	private static final String FIND_BY_ALIAS = "from "
			+ WebNotePO.class.getName()
			+ " tb where tb.alias = ? and tb.state>=?";

	public WebNotePO findByAlias(final String alias, final String username,
			final boolean isShow, final int state) {
		return (WebNotePO) dao(new Run<WebNotePO>() {
			protected WebNotePO run(EntityManager em) {
				Query query = em.createQuery(FIND_BY_ALIAS);
				query.setParameter(1, alias);
				query.setParameter(2, state);
				@SuppressWarnings("unchecked")
				List<WebNotePO> rlist = (List<WebNotePO>) query.getResultList();
				if (rlist == null || rlist.size() == 0) {
					return null;
				} else {
					WebNotePO po = rlist.remove(0);
					if (isShow || po.getUsername().equals(username)) {
						return po;
					} else {
						return null;
					}
				}
			}
		}, true);
	}

	public WebNotePO find(final Long id, final String username,
			final boolean isShow) {
		return dao(new Run<WebNotePO>() {
			@Override
			protected WebNotePO run(EntityManager em) {
				WebNotePO po = em.find(WebNotePO.class, id);
				if (isShow) {
					return po;
				}
				if (po != null && po.getUsername().equals(username)) {
					return po;
				} else {
					return null;
				}
			}
		}, true);
	}

	public boolean delete(final Long id, final String username) {
		return dao(new Run<Boolean>() {
			@Override
			protected Boolean run(EntityManager em) {
				WebNotePO po = em.find(WebNotePO.class, id);
				if (po == null) {
					return false;
				} else {
					if (po.getUsername().equals(username)) {
						em.remove(po);
						return true;
					} else {
						return false;
					}
				}
			}
		}, false);
	}

	private static final String UPDATE_HOTS = "update "
			+ WebNotePO.class.getName() + " tb set hots=hots+? where id=?";

	// @Override
	// @see ICounterable
	public int saveCounters(final HashMap<String, Integer> counters) {
		return dao(new Run<Integer>() {
			@Override
			protected Integer run(EntityManager em) {
				Set<Entry<String, Integer>> set = counters.entrySet();
				int i = 0;
				for (Entry<String, Integer> entry : set) {
					Query query = em.createQuery(UPDATE_HOTS);
					query.setParameter(1, entry.getValue());
					query.setParameter(2, new Long(entry.getKey()));
					i = i + query.executeUpdate();
				}
				return i;
			}
		}, false);
	}
}
